package initialize

import (
	"archive/zip"
	"fmt"
	"github.com/flipped-aurora/gin-vue-admin/server/config"
	"github.com/flipped-aurora/gin-vue-admin/server/global"
	"github.com/flipped-aurora/gin-vue-admin/server/utils"
	"github.com/robfig/cron/v3"
	"io"
	"log"
	"os"
	"path/filepath"
	"time"
)

func Timer() {
	if global.GVA_CONFIG.Timer.Start {
		for i := range global.GVA_CONFIG.Timer.Detail {
			go func(detail config.Detail) {
				var option []cron.Option
				if global.GVA_CONFIG.Timer.WithSeconds {
					option = append(option, cron.WithSeconds())
				}
				_, err := global.GVA_Timer.AddTaskByFunc("ClearDB", global.GVA_CONFIG.Timer.Spec, func() {
					err := utils.ClearTable(global.GVA_DB, detail.TableName, detail.CompareField, detail.Interval)
					if err != nil {
						fmt.Println("timer error:", err)
					}
				}, option...)
				if err != nil {
					fmt.Println("add timer error:", err)
				}
			}(global.GVA_CONFIG.Timer.Detail[i])
		}
	}

	go func() {
		var option []cron.Option
		option = append(option, cron.WithSeconds())

		_, err := global.GVA_Timer.AddTaskByFunc("backup", "0 */5 * * * *", func() {
			backupFiles()
			//yesterday := time.Now().AddDate(0, 0, -1)
			//today := time.Now()
			//fmt.Println("hello world", yesterday)
			//dirPath := "D:\\GOProj\\sample_data\\server\\uploads\\file"
			////dir, err := os.Open("D:\\aaa\\XXX")
			////dirPath := "E:/2024demo/sample_data/server/uploads/backup"
			//err := os.MkdirAll(dirPath, 0755)
			//if err != nil {
			//	log.Panic("创建文件夹失败:\n", err)
			//	return
			//}
			//dir, err := os.Open(dirPath)
			//if err != nil {
			//	fmt.Println("open dir error:", err)
			//}
			//defer dir.Close()
			//
			//files, err := dir.Readdir(-1)
			//if err != nil {
			//	fmt.Println("read dir error:", err)
			//}
			//// 检查是否有新文件
			//hasNewFiles := false
			//for _, file := range files {
			//	if file.IsDir() {
			//		continue // 忽略子目录
			//	}
			//	// 检查文件是否是一周前修改的
			//	if file.ModTime().After(yesterday) && file.ModTime().Before(today) {
			//		hasNewFiles = true
			//		break
			//	}
			//}
			//
			//// 如果没有新文件，则不进行备份
			//if !hasNewFiles {
			//	fmt.Println("No new files to backup.")
			//	return
			//}
			//
			//// 创建ZIP文件
			//zipFileName := fmt.Sprintf("backup_%s.zip", today.Format("2006-01-02"))
			//
			//var k string
			//err = global.GVA_DB.Raw("SELECT name FROM public.exa_file_backup WHERE key = ?;", zipFileName).Scan(&k).Error
			//if err != nil {
			//	fmt.Println("get file backup error:", err)
			//	return
			//}
			//if k != "" {
			//	fmt.Println("file backup exist")
			//	return
			//}
			//
			//zipFilePath := filepath.Join("D:\\GOProj\\sample_data\\server\\backup\\file", zipFileName)
			////检查文件是否存在
			//if _, err := os.Stat(zipFilePath); err == nil {
			//	return
			//}
			//
			//zipFile, err := os.Create(zipFilePath)
			//if err != nil {
			//	fmt.Println("Failed to create zip file:", err)
			//	return
			//}
			//defer zipFile.Close()
			//
			//// 创建zip.Writer
			//zipWriter := zip.NewWriter(zipFile)
			//defer zipWriter.Close()
			//
			//// 遍历文件
			//for _, file := range files {
			//	if file.IsDir() {
			//		continue // 忽略子目录
			//	}
			//
			//	// 检查文件的修改时间是否是前一天
			//	if file.ModTime().After(yesterday) && file.ModTime().Before(yesterday.AddDate(0, 0, 1)) {
			//		// 构建源文件路径
			//		srcPath := filepath.Join(dirPath, file.Name())
			//
			//		//// 构建目标文件路径
			//		//destPath := filepath.Join("D:\\GOProj\\sample_data\\server\\backup\\file", file.Name())
			//
			//		// 打开源文件
			//		srcFile, err := os.Open(srcPath)
			//		if err != nil {
			//			panic(err)
			//		}
			//		defer srcFile.Close()
			//
			//		var fileName string
			//		sql := "SELECT name FROM public.exa_file_upload_and_downloads WHERE key = ?;"
			//		err = global.GVA_DB.Raw(sql, file.Name()).Scan(&fileName).Error
			//		if err != nil {
			//			fmt.Println("get file error:", err)
			//		}
			//
			//		// 创建zip文件中的文件头，只使用文件名
			//		header, err := zip.FileInfoHeader(file)
			//		if err != nil {
			//			fmt.Println("Failed to create zip header:", err)
			//			continue
			//		}
			//		header.Name = fileName      // 只使用文件名
			//		header.Method = zip.Deflate // 设置压缩方法
			//		writer, err := zipWriter.CreateHeader(header)
			//		if err != nil {
			//			fmt.Println("Failed to create writer:", err)
			//			continue
			//		}
			//
			//		// 复制文件内容到zip
			//		_, err = io.Copy(writer, srcFile)
			//		if err != nil {
			//			fmt.Println("Failed to copy file to zip:", err)
			//			continue
			//		}
			//
			//	}
			//}
			//// 获取ZIP文件大小
			//zipFileInfo, err := os.Stat(zipFilePath)
			//if err != nil {
			//	log.Panic("Failed to get zip file info:", err)
			//}
			//zipFileSize := zipFileInfo.Size()
			//zipFileSizeStr := fmt.Sprintf("%d", zipFileSize)
			//err = global.GVA_DB.Exec("INSERT INTO public.exa_file_backup (id, created_at, updated_at, deleted_at, name, url, tag, key, file_size) VALUES (?, ?, ? ,? ,? ,? ,? ,?,?);",
			//	1, today, today, nil, zipFileName, "backup/file/"+zipFileName, "zip", zipFileName, zipFileSizeStr).Error
		}, option...)
		if err != nil {
			fmt.Println("add timer error:", err)
		}
		//_, err := global.GVA_Timer.AddTaskByFunc("hello", "* * * * * *", func() {
		//	fmt.Println("hello world")
		//}, option...)
		//if err != nil {
		//	fmt.Println("add timer error:", err)
		//}
	}()
}

func backupFiles() {
	yesterday := time.Now().AddDate(0, 0, -1)
	today := time.Now()
	fmt.Println("hello world", yesterday)
	dirPath := "D:\\GOProj\\sample_data\\server\\uploads\\file"
	zipPath := "D:\\GOProj\\sample_data\\server\\backup\\file"
	//dir, err := os.Open("D:\\aaa\\XXX")
	//dirPath := "E:/2024demo/sample_data/server/uploads/backup"
	err := os.MkdirAll(dirPath, 0755)
	if err != nil {
		log.Panic("创建文件夹失败:\n", err)
		return
	}
	dir, err := os.Open(dirPath)
	if err != nil {
		fmt.Println("open dir error:", err)
	}
	defer dir.Close()

	files, err := dir.Readdir(-1)
	if err != nil {
		fmt.Println("read dir error:", err)
	}
	// 检查是否有新文件
	hasNewFiles := false
	for _, file := range files {
		if file.IsDir() {
			continue // 忽略子目录
		}
		// 检查文件是否是一周前修改的
		if file.ModTime().After(yesterday) && file.ModTime().Before(today) {
			hasNewFiles = true
			break
		}
	}

	// 如果没有新文件，则不进行备份
	if !hasNewFiles {
		fmt.Println("No new files to backup.")
		return
	}

	// 创建ZIP文件
	//zipFileName := fmt.Sprintf("backup_%s.zip", today.Format("2006-01-02"))

	backupBaseName := fmt.Sprintf("backup_%s", today.Format("2006-01-02"))
	batchIndex := 1
	currentSize := int64(0)

	var k string
	err = global.GVA_DB.Raw("SELECT name FROM public.exa_file_backup WHERE key = ?;", backupBaseName).Scan(&k).Error
	if err != nil {
		fmt.Println("get file backup error:", err)
		return
	}
	if k != "" {
		fmt.Println("file backup exist")
		return
	}
	zipFileName := fmt.Sprintf("%s_%03d.zip", backupBaseName, batchIndex)
	zipFilePath := filepath.Join(zipPath, zipFileName)
	//检查文件是否存在
	if _, err := os.Stat(zipFilePath); err == nil {
		fmt.Println("file backup exist")
		return
	}

	zipFile, err := os.Create(zipFilePath)
	if err != nil {
		fmt.Println("Failed to create zip file:", err)
		return
	}
	defer zipFile.Close()

	// 创建zip.Writer
	zipWriter := zip.NewWriter(zipFile)
	defer zipWriter.Close()

	// 遍历文件
	for _, file := range files {
		if file.IsDir() {
			continue // 忽略子目录
		}

		// 检查文件的修改时间是否是前一天
		if file.ModTime().After(yesterday) && file.ModTime().Before(today) {
			// 构建源文件路径
			srcPath := filepath.Join(dirPath, file.Name())
			fileInfo, err := os.Stat(srcPath)
			if err != nil {
				log.Printf("Failed to stat file %s: %v", srcPath, err)
				continue
			}
			if currentSize+fileInfo.Size() > 5*1024*1024*1024 {
				// 获取ZIP文件大小
				zipFileInfo, err := os.Stat(zipFilePath)
				if err != nil {
					log.Panic("Failed to get zip file info:", err)
				}
				zipFileSize := zipFileInfo.Size()
				zipFileSizeStr := fmt.Sprintf("%d", zipFileSize)

				err = global.GVA_DB.Exec("INSERT INTO public.exa_file_backup (id, created_at, updated_at, deleted_at, name, url, tag, key, file_size) VALUES (?, ?, ? ,? ,? ,? ,? ,?,?);",
					1, today, today, nil, zipFileName, "backup/file/"+zipFileName, "zip", zipFileName, zipFileSizeStr).Error
				batchIndex++
				currentSize = 0
				zipFileName = fmt.Sprintf("%s_%03d.zip", backupBaseName, batchIndex)
				zipFilePath = filepath.Join(zipPath, zipFileName)
				zipFile, err = os.Create(zipFilePath)
				if err != nil {
					fmt.Println("Failed to create zip file:", err)
					return
				}
				defer zipFile.Close()

				// 创建zip.Writer
				zipWriter = zip.NewWriter(zipFile)
				defer zipWriter.Close()
				currentSize = 0

			}

			var fileName string
			sql := "SELECT name FROM public.exa_file_upload_and_downloads WHERE key = ?;"
			err = global.GVA_DB.Raw(sql, file.Name()).Scan(&fileName).Error
			if err != nil {
				fmt.Println("get file error:", err)
			}
			err = addFileToZip(zipWriter, srcPath, fileName)
			if err != nil {
				panic(err)
			}

			currentSize += fileInfo.Size()

		}

	}

	// 获取ZIP文件大小
	zipFileInfo, err := os.Stat(zipFilePath)
	if err != nil {
		log.Panic("Failed to get zip file info:", err)
	}
	zipFileSize := zipFileInfo.Size()
	zipFileSizeStr := fmt.Sprintf("%d", zipFileSize)

	err = global.GVA_DB.Exec("INSERT INTO public.exa_file_backup (id, created_at, updated_at, deleted_at, name, url, tag, key, file_size) VALUES (?, ?, ? ,? ,? ,? ,? ,?,?);",
		1, today, today, nil, zipFileName, "backup/file/"+zipFileName, "zip", zipFileName, zipFileSizeStr).Error

}

func addFileToZip(zipWriter *zip.Writer, filePath, fileName string) error {
	// 打开源文件
	srcFile, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	// 获取文件信息
	fileInfo, err := srcFile.Stat()
	if err != nil {
		return err
	}

	// 创建zip文件中的文件头
	header, err := zip.FileInfoHeader(fileInfo)
	if err != nil {
		return err
	}
	header.Name = fileName      // 设置压缩文件中的文件名
	header.Method = zip.Deflate // 设置压缩方法

	// 创建zip.Writer的文件
	writer, err := zipWriter.CreateHeader(header)
	if err != nil {
		return err
	}

	// 复制文件内容到zip
	_, err = io.Copy(writer, srcFile)
	return err
}
